import {
  CanActivate,
  ExecutionContext,
  Injectable,
  SetMetadata,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport';
import { Observable } from 'rxjs';

export const JWT_GUARD_NAME = 'my-jwt-guard';
export const IS_PUBLIC_KEY = 'the-route-is-public-for-jwt';
export const PublicRoute = () => SetMetadata(IS_PUBLIC_KEY, true);
export const PrivateRoute = () => SetMetadata(IS_PUBLIC_KEY, false);

@Injectable()
export class JwtGuard extends AuthGuard(JWT_GUARD_NAME) implements CanActivate {
  constructor(private reflector: Reflector) {
    super();
  }

  // 判断 guard守卫 阶段是否可以通过验证
  canActivate(
    context: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean> {
    // 因为 jwt-guard 将配置到全局，所有的接口都会被拦截
    // 所以需要设置一个可以绕开 jwt 验证的功能

    // 从 context 中获取当前 route 所配置的 meta
    // 从而判断当前 route 是否是公开的
    const isPublicRoute = this.reflector.getAllAndOverride<boolean>(
      IS_PUBLIC_KEY,
      [context.getHandler(), context.getClass()],
    );

    console.log('jwt guard', { isPublicRoute });

    // 如果是公开的路由，直接通过
    // 否则调用父类的校验方法（我们实现的 jwt-strategy）
    return isPublicRoute || super.canActivate(context);
  }
}
